package com.gitee.sop.websiteserver.service;

import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.PageInfo;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.fastmybatis.core.query.Sort;
import com.gitee.fastmybatis.core.util.MapperUtil;
import com.gitee.sop.gatewaycommon.bean.IsvRoutePermission;
import com.gitee.sop.gatewaycommon.bean.NacosConfigs;
import com.gitee.sop.gatewaycommon.sync.MyNamedThreadFactory;
import com.gitee.sop.gatewaycommon.util.CopyUtil;
import com.gitee.sop.websiteserver.bean.*;
import com.gitee.sop.websiteserver.controller.param.IsvPageParam;
import com.gitee.sop.websiteserver.controller.param.RegParam;
import com.gitee.sop.websiteserver.entity.*;
import com.gitee.sop.websiteserver.mapper.*;
import com.gitee.sop.websiteserver.util.GenerateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
@Slf4j
public class UserService {

    public static final byte STATUS_ENABLE = 1;

    private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 4,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(), new MyNamedThreadFactory("push-thread"));

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private IsvInfoMapper isvInfoMapper;

    @Autowired
    private IsvKeysMapper isvKeysMapper;

    @Autowired
    private PermIsvRoleMapper permIsvRoleMapper;

    @Autowired
    private ConfigPushService configPushService;

    @Autowired
    private PermRolePermissionMapper permRolePermissionMapper;


    public UserAccount getUserAccountByUsername(String username) {
        return userAccountMapper.getByColumn("username", username);
    }

    public UserAccount getUserAccountByUserId(long userId) {
        return userAccountMapper.getByColumn("id", userId);
    }

    public void updateUserAccount(UserAccount userAccount) {
        userAccountMapper.updateIgnoreNull(userAccount);
    }

    public UserAccount getUserInfoAppKey(String appKey) {
        return userAccountMapper.getByColumn("app_key", appKey);
    }

    public IsvPortal getIsvPortal(long userId) {
        return isvInfoMapper.getIsvPortal(userId);
    }

    public PageInfo<IsvInfo> getIsvInfoList(long userId, IsvPageParam pageParam) {
        Query query = Query.build(pageParam);
        query.eq("user_id", userId);
        query.orderby("gmt_create", Sort.DESC);
        PageInfo<IsvInfo> pageInfo = MapperUtil.query(isvInfoMapper, query);
        return pageInfo;
    }

    public IsvKeys getIsvKeys(String appKey) {
        return isvKeysMapper.getByColumn("app_key", appKey);
    }

    public void saveIsvKey(IsvKeys isvKeys) {
        isvKeysMapper.saveIgnoreNull(isvKeys);
    }

    /**
     * 保存用户秘钥
     *
     * @param isvKeys
     */
    public void updateIsvKey(IsvKeys isvKeys) {
        isvKeysMapper.updateIgnoreNull(isvKeys);
    }

    public void sendChannelMsg(String appKey) {
        threadPoolExecutor.execute(() -> {
            IsvDetailDTO isvDetail = isvInfoMapper.getIsvDetail(appKey);
            if (isvDetail == null) {
                return;
            }
            ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ISV_INFO_UPDATE, isvDetail);
            configPushService.publishConfig(NacosConfigs.DATA_ID_ISV, NacosConfigs.GROUP_CHANNEL, channelMsg);

            List<String> roleCodeList = new ArrayList<>();
            roleCodeList.add("open");
            sendIsvRolePermissionMsg(appKey, roleCodeList);
        });
    }

    /**
     * 推送isv路由权限
     *
     * @param appKey
     * @param roleCodeList
     */
    public void sendIsvRolePermissionMsg(String appKey, List<String> roleCodeList) {
        Collections.sort(roleCodeList);
        List<String> routeIdList = this.getRouteIdList(roleCodeList);
        String roleCodeListMd5 = DigestUtils.md5Hex(JSON.toJSONString(routeIdList));
        IsvRoutePermission isvRoutePermission = new IsvRoutePermission();
        isvRoutePermission.setAppKey(appKey);
        isvRoutePermission.setRouteIdList(routeIdList);
        isvRoutePermission.setRouteIdListMd5(roleCodeListMd5);
        ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ROUTE_PERMISSION_UPDATE, isvRoutePermission);
        configPushService.publishConfig(NacosConfigs.DATA_ID_ROUTE_PERMISSION, NacosConfigs.GROUP_CHANNEL, channelMsg);

    }

    public List<String> getRouteIdList(List<String> roleCodeList) {
        if (CollectionUtils.isEmpty(roleCodeList)) {
            return Collections.emptyList();
        }
        Query query = new Query();
        query.in("role_code", roleCodeList);
        List<PermRolePermission> rolePermissionList = permRolePermissionMapper.list(query);
        return rolePermissionList.stream()
                .map(PermRolePermission::getRouteId)
                .sorted()
                .collect(Collectors.toList());
    }

    public LoginUser getLoginUser(String username, String password) {
        UserAccount login = userAccountMapper.login(username, password);
        if (Objects.nonNull(login)) {
            LoginUser loginUser = new LoginUser();
            loginUser.setUserId(login.getId());
            loginUser.setStatus(login.getStatus());
            return loginUser;
        }
        return null;
    }

    public UserAccount saveUser(RegParam param) {
        UserAccount userInfo = new UserAccount();
        String password = GenerateUtil.getUserPassword(param.getUsername(), param.getPassword());
        userInfo.setUsername(param.getUsername());
        userInfo.setPassword(password);
        userInfo.setStatus(STATUS_ENABLE);
        userAccountMapper.saveIgnoreNull(userInfo);
        return userInfo;
    }

    public void createIsv(Long userId, String remark) {
        String appKey = new SimpleDateFormat("yyyyMMdd").format(new Date()) + IdGen.nextId();
        IsvInfo rec = new IsvInfo();
        rec.setAppKey(appKey);
        rec.setUserId(userId);
        rec.setStatus(STATUS_ENABLE);
        rec.setRemark(remark);
        isvInfoMapper.saveIgnoreNull(rec);
        IsvKeysGenVO isvKeysGenVO = null;
        try {
            isvKeysGenVO = this.createIsvKeys();
        } catch (Exception e) {
            throw new RuntimeException("创建ISV秘钥失败", e);
        }
        IsvKeys isvKeys = new IsvKeys();
        isvKeys.setAppKey(appKey);
        isvKeys.setSignType((byte) 1);
        CopyUtil.copyPropertiesIgnoreNull(isvKeysGenVO, isvKeys);
        isvKeysMapper.saveIgnoreNull(isvKeys);

        //默认拥有公开角色
        PermIsvRole permIsvRole = new PermIsvRole();
        permIsvRole.setIsvId(rec.getId());
        permIsvRole.setRoleCode("open");
        permIsvRole.setGmtCreate(new Date());
        permIsvRole.setGmtModified(permIsvRole.getGmtCreate());
        permIsvRoleMapper.save(permIsvRole);

        this.sendChannelMsg(rec.getAppKey());
    }

    public void updateIsv(Long id, String remark, byte status) {
        IsvInfo isvInfo = getIsvInfo(id);
        if (Objects.nonNull(isvInfo)) {
            Byte oldStatus = isvInfo.getStatus();
            isvInfo.setStatus(status);
            isvInfo.setRemark(remark);
            isvInfoMapper.update(isvInfo);
            if (oldStatus.byteValue() != status) {
                this.sendChannelMsg(isvInfo.getAppKey());
            }
        }
    }

    public void deleteIsv(String appKey, Long userId) {
        Query query = new Query();
        query.eq("user_id", userId);
        query.eq("app_key", appKey);
        IsvInfo isvInfo = isvInfoMapper.getByQuery(query);
        if (Objects.nonNull(isvInfo)) {
            isvInfo.setStatus((byte) 2);
            isvInfoMapper.update(isvInfo);
            this.sendChannelMsg(appKey);

            //删除应用信息
            isvInfoMapper.deleteById(isvInfo.getId());
            //删除应用key
            isvKeysMapper.deleteIsvKeys(appKey);
            //删除相关角色关联
            permIsvRoleMapper.deleteRoles(isvInfo.getId());


        }
    }

    public IsvInfo getIsvInfo(Long id) {
        return isvInfoMapper.getById(id);
    }

    private IsvKeysGenVO createIsvKeys() throws Exception {
        IsvKeysGenVO isvFormVO = new IsvKeysGenVO();
        String secret = IdGen.uuid();

        isvFormVO.setSecret(secret);

        RSATool rsaToolIsv = new RSATool(RSATool.KeyFormat.PKCS8, RSATool.KeyLength.LENGTH_2048);
        RSATool.KeyStore keyStoreIsv = rsaToolIsv.createKeys();
        isvFormVO.setPublicKeyIsv(keyStoreIsv.getPublicKey());
        isvFormVO.setPrivateKeyIsv(keyStoreIsv.getPrivateKey());

        RSATool platFormIsv = new RSATool(RSATool.KeyFormat.PKCS8, RSATool.KeyLength.LENGTH_2048);
        RSATool.KeyStore platFormKeyStoreIsv = platFormIsv.createKeys();
        isvFormVO.setPublicKeyPlatform(platFormKeyStoreIsv.getPublicKey());
        isvFormVO.setPrivateKeyPlatform(platFormKeyStoreIsv.getPrivateKey());
        return isvFormVO;
    }


}
